import bit.field.EnumSetText;
import bit.field.Text;
import ordinal.EnsembleEnum;
import ordinal.EnsembleOrdinal;
import ordinal.index.Herb;

import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;

/**
 * 场景类
 */
public class EnumTest {
    public static void main(String[] args) {
//        enum31_InstanceFields();
//        enum32_EnumSetInsteadOfBitField();
          enum33_EnumMapInsteadOfOrdinalIndex();
//        ## 30 用enum代替int常量


//        ## 33 用EnumMap 代替序数索引
//        ## 34 用接口模拟可伸缩的枚举

//        ## 35 注解优先于命名模式

//        ## 36 坚持使用Override注解

//        ## 37 用标记接口定义类型


    }

    /**
     * 31 用实例域代替序数
     */
    public static void enum31_InstanceFields() {
        // ordinal() 直接返回序号
        System.out.println("序号: " +  EnsembleOrdinal.DUET.numberOfMusicians());
        // 实例域
        System.out.println("实例域: " + EnsembleEnum.DUET.getNumberOfMusicians());
    }

    /**
     * 32 用 `EnumSet` 代替位域 (bit field)
     */
    public static void enum32_EnumSetInsteadOfBitField() {
        Text t = new Text();
        // 位域
        t.applayStyles(Text.STYLE_BOLD | Text.STYLE_STRIKETHROUGH);

        // EnumSet 代替 位域
        EnumSetText et = new EnumSetText();

        // EnumSet.of(...)  合并为一个
        et.applyStyle(EnumSet.of(EnumSetText.Style.BOLD, EnumSetText.Style.STRIKETHROUGH));
    }

    /**
     * 33 用 EnumSet 代替 序数索引
     */
    public static void enum33_EnumMapInsteadOfOrdinalIndex() {
        // 需求: 给花园中的香草按照类型进行组织输出 (分组)

        // Using ordinal() to index an array - DON'T DO THIS!
        Herb[] garden = {
                new Herb("一年生", Herb.TypeEnum.ANNUAL),
                new Herb("两年生", Herb.TypeEnum.BIENNIAL),
                new Herb("三年生", Herb.TypeEnum.PREENNIAL)
        };

        // 1. 方法一: 通过序列数索引 Indexed by Herb.TypeEnum.ordinal()
        /*
        存在问题:
            1.1 数组不能域泛型兼容(第 25 条)
            1.2
        */
        // 创建一个包含所有类型的集合
        Set<Herb>[]  hrebByType = new Set[Herb.TypeEnum.values().length];

        for (int i = 0; i < hrebByType.length; i++) {
            hrebByType[i] = new HashSet<Herb>();
        }
        // 将每种类型的香草放入数组中
        for (Herb g : garden) {
            // 按照类型的序号索引
            hrebByType[g.getType().ordinal()].add(g);
        }
        // 打印结果
        for (int i = 0; i < hrebByType.length; i++) {
            System.out.printf("%s: %s%n", Herb.TypeEnum.values()[i],
                    hrebByType[i]);
        }

        // 2. 方法二

    }


    // 34 用接口模拟可伸缩的枚举
    public static void enum34_EmulatedExtensibleEnmUsingAnInterface() {
        // 虽然枚举类型(BasicOperationImpl) 不是可扩展的, 但是接口类型(IOperation)是可以扩展的;
//         IOperation operation = new BasicOperationImpl();
//        IOperation extendOperaton = new ExtendOperationImpl();


    }

    public static void todo() {
        for (OperationEnum o : OperationEnum.values()) {
            System.out.printf("%s ,", o);
        }

        // 枚举中的方法
        @Deprecated
        double result = OperationEnum.PLUS.apply(0.2, 0.4);
        System.out.printf("result : %s %n", result);

        // 特定于常量的类主体中声明一个抽象方法
        // 特定于常量的方法实现
        // 这样在添加新常量时就不会忘记提供apply方法
        for (Operation2Enum o2 : Operation2Enum.values()) {
            System.out.printf(" %s , ", o2);
        }
        double result2 = Operation2Enum.PLUS.apply(0.2, 0.4);
        System.out.printf("result2 : %s , " , result2);
        // 覆写 toString()
        System.out.println(Operation2Enum.PLUS.toString());

        // 枚举策略
    }


}
